package com.tuanzi.loan.web.bean.system.workflow;

import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.faces.bean.ViewScoped;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.model.LazyDataModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.collect.Lists;
import com.tuanzi.loan.business.entity.system.Role;
import com.tuanzi.loan.business.entity.system.SystemUser;
import com.tuanzi.loan.business.service.system.RoleService;
import com.tuanzi.loan.business.service.system.SystemUserService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.vo.request.system.RoleSearchRequest;
import com.tuanzi.loan.vo.request.system.SystemUserSearchRequest;
import com.tuanzi.loan.vo.response.system.RoleSearchResponse;
import com.tuanzi.loan.vo.response.system.SystemUserSearchResponse;
import com.tuanzi.loan.web.configuration.JSFBean;
import com.tuanzi.loan.web.lazy.system.RoleLazyDataModel;
import com.tuanzi.loan.web.lazy.system.SystemUserLazyDataModel;
import com.tuanzi.loan.workflow.entity.ScriptTask;
import com.tuanzi.loan.workflow.entity.ScriptTaskType;
import com.tuanzi.loan.workflow.service.ScriptTaskService;
import com.tuanzi.loan.workflow.service.WorkflowManagerService;
import com.tuanzi.loan.workflow.vo.ActivityResponse;
import com.tuanzi.loan.workflow.vo.AssigneeResponse;
import com.tuanzi.loan.workflow.vo.AssigneeType;

import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * @author Ray 2017/09/22
 */
@Data
@Debug
@Component
@ViewScoped
@EqualsAndHashCode(callSuper = true)
public class WorkflowNodeBean extends JSFBean {

	private static final long serialVersionUID = -2152778554108785342L;

	@Autowired
	private WorkflowManagerService workflowManagerService;
	@Autowired
	private RoleService roleService;
	@Autowired
	private SystemUserService systemUserService;
	@Autowired
	private ScriptTaskService scriptTaskService;
	private String preScriptTaskContent;
	private String postScriptTaskContent;
	private String transScriptTaskContent;
	private List<ActivityResponse> activityResponses;
	private String procDefId;
	private ActivityResponse selectedActivityResponse;

	private List<AssigneeResponse> roleAssignees;
	private List<AssigneeResponse> userAssignees;

	private SystemUserSearchRequest systemUserSearchRequest;
	private RoleSearchRequest roleSearchRequest;
	private LazyDataModel<SystemUserSearchResponse> systemUserLazyDataModel;
	private LazyDataModel<RoleSearchResponse> roleLazyDataModel;
	private String assigneeVariable;
	private String formUrl;

	@PostConstruct
	private void init() {
		systemUserSearchRequest = new SystemUserSearchRequest();
		roleSearchRequest = new RoleSearchRequest();
		systemUserLazyDataModel = new SystemUserLazyDataModel(systemUserSearchRequest);
		roleLazyDataModel = new RoleLazyDataModel(roleSearchRequest);
	}

	public void onLoadNodeData() {
		selectedActivityResponse = null;
		activityResponses = workflowManagerService.findAllActivity(procDefId);
	}

	public void onSave() {
		workflowManagerService.saveActivity(procDefId, activityResponses);
		addSuccessfullyMessage();
	}

	public void onRowSelect() {
		classifyAssignee();
		formUrl = selectedActivityResponse.getFormUrl();
		assigneeVariable = selectedActivityResponse.getAssigneeVariable();
	}

	public void onEditScriptTask() {
		preScriptTaskContent = StringUtils.EMPTY;
		postScriptTaskContent = StringUtils.EMPTY;
		transScriptTaskContent = StringUtils.EMPTY;

		for (ScriptTask scriptTask : selectedActivityResponse.getScriptTasks()) {
			switch (scriptTask.getTaskType()) {
			case PRE:
				preScriptTaskContent = scriptTask.getContent();
				break;
			case POST:
				postScriptTaskContent = scriptTask.getContent();
				break;
			case TRANS:
				transScriptTaskContent = scriptTask.getContent();
				break;
			}
		}
	}

	private void classifyAssignee() {
		userAssignees = Lists.newArrayList();
		roleAssignees = Lists.newArrayList();
		for (AssigneeResponse assigneeResponse : selectedActivityResponse.getAssignees()) {
			switch (assigneeResponse.getAssigneeType()) {
			case USER:
				userAssignees.add(assigneeResponse);
				break;
			case ROLE:
				roleAssignees.add(assigneeResponse);
				break;
			}
		}
	}

	public boolean isAssignedUser(String account) {
		if (CollectionUtils.isEmpty(userAssignees)) {
			return false;
		}
		return userAssignees.parallelStream().filter(x -> StringUtils.equals(x.getAssignee(), account)).count() > 0;
	}

	public boolean isAssignedRole(String roleCode) {
		if (CollectionUtils.isEmpty(roleAssignees)) {
			return false;
		}
		return roleAssignees.parallelStream().filter(x -> StringUtils.equals(x.getAssignee(), roleCode)).count() > 0;
	}

	public void onSelectUser(String account) {
		SystemUser systemUser = systemUserService.findOneByAccount(account);
		AssigneeResponse assigneeResponse = new AssigneeResponse();
		assigneeResponse.setActivityId(selectedActivityResponse.getActivityId());
		assigneeResponse.setAssignee(systemUser.getAccount());
		assigneeResponse.setAssigneeName(systemUser.getName());
		assigneeResponse.setAssigneeType(AssigneeType.USER);
		userAssignees.add(assigneeResponse);
	}

	public void onSubmitRole() {
		List<AssigneeResponse> assigneeResponses = Lists.newArrayList();
		assigneeResponses.addAll(userAssignees);
		assigneeResponses.addAll(roleAssignees);
		selectedActivityResponse.setAssignees(assigneeResponses.parallelStream().distinct().collect(Collectors.toList()));
	}

	public void onSubmitUser() {
		List<AssigneeResponse> assigneeResponses = Lists.newArrayList();
		assigneeResponses.addAll(userAssignees);
		assigneeResponses.addAll(roleAssignees);
		selectedActivityResponse.setAssignees(assigneeResponses.parallelStream().distinct().collect(Collectors.toList()));
	}

	public void onSubmitVariables() {
		selectedActivityResponse.setAssigneeVariable(assigneeVariable);
	}

	public void onSubmitFormUrl() {
		selectedActivityResponse.setFormUrl(formUrl);
	}

	public void onSubmitScriptTask() {

		List<ScriptTask> scriptTasks = Lists.newArrayList();

		ScriptTask preScriptTask = new ScriptTask();
		preScriptTask.setActivityId(selectedActivityResponse.getActivityId());
		preScriptTask.setProcDefId(selectedActivityResponse.getProcessDefinitionId());
		preScriptTask.setContent(preScriptTaskContent);
		preScriptTask.setTaskType(ScriptTaskType.PRE);
		scriptTasks.add(preScriptTask);

		ScriptTask postScriptTask = new ScriptTask();
		postScriptTask.setActivityId(selectedActivityResponse.getActivityId());
		postScriptTask.setProcDefId(selectedActivityResponse.getProcessDefinitionId());
		postScriptTask.setContent(postScriptTaskContent);
		postScriptTask.setTaskType(ScriptTaskType.POST);
		scriptTasks.add(postScriptTask);

		ScriptTask transScriptTask = new ScriptTask();
		transScriptTask.setActivityId(selectedActivityResponse.getActivityId());
		transScriptTask.setProcDefId(selectedActivityResponse.getProcessDefinitionId());
		transScriptTask.setContent(transScriptTaskContent);
		transScriptTask.setTaskType(ScriptTaskType.TRANS);
		scriptTasks.add(transScriptTask);

		checkScriptGrammar(scriptTasks);

		selectedActivityResponse.setScriptTasks(scriptTasks);
		execute("PF('workflowScriptTaskWidgetVar').hide();");
	}

	public void checkScriptGrammar(List<ScriptTask> scriptTasks) {
		for (ScriptTask scriptTask : scriptTasks) {
			boolean ok = scriptTaskService.checkGroovyScript(scriptTask.getContent());

			if (!ok) {
				switch (scriptTask.getTaskType()) {
				case PRE:
					throw new SystemException("【前置任务】编译错误,请检查Groovy脚本语法");
				case POST:
					throw new SystemException("【后置任务】编译错误,请检查Groovy脚本语法");
				case TRANS:
					throw new SystemException("【转办任务】编译错误,请检查Groovy脚本语法");
				default:
					throw new SystemException("【任务】编译错误,请检查Groovy脚本语法");
				}
			}
		}

	}

	public void onUnselectUser(String account) {
		userAssignees = userAssignees.parallelStream().filter(x -> !StringUtils.equals(x.getAssignee(), account)).collect(Collectors.toList());
	}

	public void onSelectRole(String roleCode) {
		Role role = roleService.findByCode(roleCode);
		AssigneeResponse assigneeResponse = new AssigneeResponse();
		assigneeResponse.setActivityId(selectedActivityResponse.getActivityId());
		assigneeResponse.setAssignee(role.getCode());
		assigneeResponse.setAssigneeName(role.getName());
		assigneeResponse.setAssigneeType(AssigneeType.ROLE);
		roleAssignees.add(assigneeResponse);
	}

	public void onUnselectRole(String roleCode) {
		roleAssignees = roleAssignees.parallelStream().filter(x -> !StringUtils.equals(x.getAssignee(), roleCode)).collect(Collectors.toList());
	}

}
